const fs = require('fs');
const axios = require('axios');
const { ensureDirSync, resolveSafePath, safeJoin } = require('../utils/pathUtils');

async function downloadToFile(job, logger, onProgress) {
    const { file_url: fileUrl, file_name: fileName, save_path: savePath } = job;

    const targetDir = resolveSafePath(savePath || '.');
    ensureDirSync(targetDir);
    const fullPath = safeJoin(targetDir, fileName);

    const response = await axios.get(fileUrl, { responseType: 'stream', validateStatus: null });
    if (response.status < 200 || response.status >= 300) {
        const message = `HTTP ${response.status} when fetching ${fileUrl}`;
        const error = new Error(message);
        error.code = 'HTTP_ERROR';
        throw error;
    }

    const totalBytesHeader = response.headers['content-length'];
    const totalBytes = totalBytesHeader ? Number(totalBytesHeader) : null;

    const writeStream = fs.createWriteStream(fullPath);

    let receivedBytes = 0;
    let lastReportTimeMs = Date.now();
    let lastReportBytes = 0;

    const progressHandler = () => {
        const now = Date.now();
        const elapsedMs = now - lastReportTimeMs;
        if (elapsedMs >= 1000) {
            const bytesDelta = receivedBytes - lastReportBytes;
            const speedBps = Math.floor((bytesDelta * 1000) / elapsedMs);
            const percent = totalBytes ? Math.floor((receivedBytes / totalBytes) * 100) : null;
            lastReportTimeMs = now;
            lastReportBytes = receivedBytes;
            if (onProgress) onProgress({ receivedBytes, totalBytes, percent, speedBps });
        }
    };

    return new Promise((resolve, reject) => {
        response.data.on('data', (chunk) => {
            receivedBytes += chunk.length;
            progressHandler();
        });

        response.data.on('error', (err) => {
            logger && logger.error({ err }, 'download stream error');
            reject(err);
        });

        writeStream.on('error', (err) => {
            logger && logger.error({ err }, 'write stream error');
            reject(err);
        });

        writeStream.on('finish', () => {
            // Final progress emit
            const percent = totalBytes ? Math.floor((receivedBytes / totalBytes) * 100) : null;
            if (onProgress) onProgress({ receivedBytes, totalBytes, percent, speedBps: 0 });
            resolve({ fullPath, totalBytes, receivedBytes });
        });

        response.data.pipe(writeStream);
    });
}

module.exports = {
    downloadToFile,
};


